package com.pig4cloud.pig.common.feign.config;

import com.bblocks.http.converter.FuryHttpMessageConverter;
import com.bblocks.http.converter.KryoHttpMessageConverter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import com.pig4cloud.pig.common.core.config.JacksonConfiguration;
import com.pig4cloud.pig.common.feign.annotation.EnablePigFeignClients;
import com.pig4cloud.pig.common.feign.handle.FeginInterceptor;
import feign.codec.Decoder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cache.CacheManager;
import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
import org.springframework.cloud.openfeign.support.SpringDecoder;
import org.springframework.context.annotation.*;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;

import javax.annotation.Resource;

/**
 * 综合编码方案（大前提：服务提供方支持此编码，默认mvc默认响应编码是json）
 * 1、目前支持kryo、json,Fury
 * 2、由 EnablePigFeignClients.extraDecoder 启动附加编码
 * 3、feign head添加Accept=xxx,例如： application/x-kryo-serialization，以支持kryo编码
 *    a、接口注解添加head
 *    b、拦截器统一添加head
 * https://www.lmlphp.com/user/56/article/item/10076/
 */
//@Import({ FeignCodecConfiguration.FeignCodecExtraConfiguration.class})
@Slf4j
public class FeignCodecConfiguration /*implements ImportBeanDefinitionRegistrar*/{
	private final static String EXTRA_DECODER_KEY = "extraDecoder";

	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		//1. 从BeanIocScan注解获取到我们要搜索的包路径
		AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(EnablePigFeignClients.class.getName()));
		if (annoAttrs == null || annoAttrs.isEmpty()) {
			return;
		}

		Boolean extraDecoder = (Boolean) annoAttrs.get(EXTRA_DECODER_KEY);
		if (extraDecoder != null && extraDecoder) {
			BeanDefinition beanDefinition = new GenericBeanDefinition();
			beanDefinition.setBeanClassName(SpringDecoder.class.getName());
			HttpMessageConverters allConverters = httpMessageConverters();
			ObjectFactory<HttpMessageConverters> messageConverters = () -> allConverters;
			beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(messageConverters);
			//这里注册bean
			registry.registerBeanDefinition("feignExtraConverters", beanDefinition );
		}
	}

	/**
	 * 通用json支持
	 * @param objectMapper
	 * @return
	 */
	@Bean
	public Decoder feignDecoder(ObjectMapper objectMapper) {
		return new ResponseEntityDecoder(new SpringDecoder(() -> new HttpMessageConverters(getJsonConverter(objectMapper))));
	}



	/**
	 * 新添加的编码（json之外的）
	 * @return
	 */
	private static HttpMessageConverters httpMessageConverters(){
		HttpMessageConverters converters  = new HttpMessageConverters(Lists.newArrayList(getKryoConverter(),getFuryConverter()));
		return converters;
	}

	/**
	 * 默认自带，本初暂时不生效执行
	 * @return
	 */
	private static MappingJackson2HttpMessageConverter getJsonConverter(ObjectMapper objectMapper) {
		MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter(objectMapper);
		return mappingJackson2HttpMessageConverter;
	}

	private static  KryoHttpMessageConverter getKryoConverter() {
		KryoHttpMessageConverter kryoMessageConverter = new KryoHttpMessageConverter();
		return kryoMessageConverter;
	}



	private static FuryHttpMessageConverter getFuryConverter() {
		FuryHttpMessageConverter furyHttpMessageConverter = new FuryHttpMessageConverter();
		return furyHttpMessageConverter;
	}

	/**
	 * 加载其他编码（由EnablePigFeignClients.extraDecoder 决定）
	 */
	public static class FeignCodecExtraConfiguration implements ImportBeanDefinitionRegistrar {
		public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
			//1. 从BeanIocScan注解获取到我们要搜索的包路径
			AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(EnablePigFeignClients.class.getName()));
			if (annoAttrs == null || annoAttrs.isEmpty()) {
				return;
			}

			Boolean extraDecoder = (Boolean) annoAttrs.get(EXTRA_DECODER_KEY);
			if (extraDecoder != null && extraDecoder) {
				BeanDefinition beanDefinition = new GenericBeanDefinition();
				beanDefinition.setBeanClassName(SpringDecoder.class.getName());
				HttpMessageConverters allConverters = httpMessageConverters();
				ObjectFactory<HttpMessageConverters> messageConverters = () -> allConverters;
				beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(messageConverters);
				//这里注册bean
				registry.registerBeanDefinition("feignExtraConverters", beanDefinition );
			}
		}
	}

}
